package com.hbnu.service;

import com.hbnu.dao.UserDao;
import com.hbnu.dao.UserFileDao;
import com.hbnu.entity.FileStat;
import com.hbnu.entity.UserFile;
import com.hbnu.enums.Status;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import static com.hbnu.tools.PathTool.*;
import static com.hbnu.tools.PrintTool.*;
import static com.hbnu.tools.PrintTool.println;
import static com.hbnu.tools.ScannerTool.nextLine;
import static com.hbnu.tools.UserFileTool.*;
import static com.hbnu.web.Client.*;
import static com.hbnu.web.Client.pathIdMap;

public class UserFileService extends AbstractFunctionService {
    private final UserFileDao userFileDao=new UserFileDao();
    private final UserDao userDao=new UserDao();
    public UserFileService(){
        cmdMap.put("pwd",this::pwd);
        cmdMap.put("list",this::list);
        cmdMap.put("tree",this::tree);
        cmdMap.put("idtree",this::idtree);
        cmdMap.put("ls",this::ls);
        cmdMap.put("cd",this::cd);

        oneMap.put("cd",this::cd);
        oneMap.put("cid",this::cid);
        oneMap.put("stat",this::stat);
        oneMap.put("sid",this::sid);
        oneMap.put("mkdir",this::mkdir);
        oneMap.put("rm",this::rm);
        oneMap.put("rid",this::rid);


        twoMap.put("rename",this::rename);
        twoMap.put("renameid",this::renameid);
        twoMap.put("mv",this::mv);
        twoMap.put("mvid",this::mvid);
    }

    private void pwd(){
        println(folder.getPath());
    }
    //查看当前表格
    private  void list() {
        UserFile file = idUserFileMap.get(folder.getFid());
        if(!file.hasChildren()) return;//无子内容不显示
        // 打印表格
        printList(file);
    }
    //查看文件数结构
    private  void tree() {
        UserFile file = idUserFileMap.get(folder.getFid());
        if(!file.hasChildren()) return;//无子内容不显示
        // 打印表格
        printUserFileTree(file);
    }
    private  void idtree() {
        UserFile file = idUserFileMap.get(folder.getFid());
        if(!file.hasChildren()) return;//无子内容不显示
        // 打印表格
        printIdTree(file);
    }
    //查看当前文件夹下的文件
    private void ls() {
        UserFile file = idUserFileMap.get(folder.getFid());
        if(file==null) {
            cd();return;
        }
        if(!file.hasChildren()) return;//无子内容不显示
        // 打印表格
        printLS(file);
    }


    //切换路径 改变了文件夹id,path和 tip的name
    private void cd() {
        //不是根，回到跟
        if(!"~".equals(folder.getPath())) {
            cd0(user.getFolder_id());
        }
    }
    private void cd(String p) {
        //判断是否存在,并且为文件夹
        cd0(getFolder(p,true));
    }
    private void cid(String id) {
        cd0(getFolder(id,false));
    }
    private void cd0(int fid){
        UserFile userFile=idUserFileMap.get(fid);
        folder.setFid(userFile.getFid());//用户中有，文件夹根id字段
        folder.setPath(userFile.getPath());
        setTip(userFile.getFname());
    }
    //查看文件详情、通过id查看
    private void stat(String p) {
        stat0(getFile(p,true));
    }
    private void sid(String id) {
        stat0(getFile(id,false));
    }
    private void stat0(int fid) {
        //地址转换
        FileStat fileStat = getFileStat(fid);
        println(fileStat);//打印文件信息
    }
    public FileStat getFileStat(int fid){
        if(!fileStatMap.containsKey(fid)){
            //该操作比较耗时，查询后加入map集合进行缓存
            FileStat fileStat = userFileDao.getFile(fid);
            fileStatMap.put(fid,fileStat);//进行缓存
        }
        return fileStatMap.get(fid);
    }

    //创建文件夹--->判断父文件夹是否存在，再创建
    private void mkdir(String p) {
        String path = calcPath(folder.getPath(), p);
        //判断父级是否存在
        String fPath = getParentPath(path);
        Integer pid = pathIdMap.get(fPath);
        //绝对路径创建 /s
        if(!folder.getPath().equals(fPath)) {
            //父级不存在
            if (null == pid) {
                throw new RuntimeException("路径错误!");
            }
            //父级是文件
            if (idUserFileMap.get(pid).is_file()) {
                throw new RuntimeException("父级不能是文件!");
            }
        }
        //就地创建文件 父级就是此文件
        String name = getPathName(path);
        //判断名称是否存在
        mkdir(path,name,pid);
    }
    public int mkdir(String path,String name,int pid) {
        //判断名称是否存在
        if (existFName(pid, name)) {
            throw new RuntimeException("名称已存在!");
        }
        //创建成功返回fid
        int fid=userFileDao.createFolder(user.getUid(), pid, name);
        //将文件夹加入map
        pathIdMap.put(path,fid);
        idUserFileMap.get(pid).addList(fid);//添加到父id
        idUserFileMap.put(fid,new UserFile(fid,pid,name,0,false,path));
        return fid;
    }



    //删除文件  id版 删除自己:只影响显示
    private void rm(String p) {
        rm0(pathToFid(p));
    }
    private void rid(String id) {
        rm0(idToFid(id));
    }
    private void rm0(int fid){
        if(fid== user.getFolder_id()){
           throw  new RuntimeException("不能删除根目录");
        }
        UserFile userFile = idUserFileMap.get(fid);
        boolean is_file=userFile.is_file();
        if(is_file) {
            print("rm: 删除文件 \"" + userFile.getFname() + "\"?(y/n): ");
        } else {
            print("rm: 删除文件夹(文件夹内容将全部删除!) \"" + userFile.getFname() + "\"?(y/n): ");
        }
        if (nextLine().equalsIgnoreCase("Y")) {
            boolean ok;
            if (is_file) {
                ok = userFileDao.deleteF(fid);
            } else {
                ok = userFileDao.deleteFolder(fid);
            }
            if (ok) {
                //清除空间
                long size=getFSize(fid);//文件大小
                if(size!=0) userDao.updateReduceSize(user.getUid(),size);
                user.setSize(user.getSize()-size);
                //异常方法
                removeChild(userFile);
                pathIdMap.remove(userFile.getPath());//删除本地path缓存
                idUserFileMap.remove(fid);//删除文件信息缓
                //删除子内容
                if (userFile.hasChildren()) {
                    Queue<Integer> queue = new LinkedList<>(userFile.getList());
                    while (!queue.isEmpty()) {
                        Integer i = queue.poll();
                        UserFile file = idUserFileMap.get(i);
                        //保存子路径
                        if (file.hasChildren()) {
                            queue.addAll(file.getList());
                        }
                        //删除
                        pathIdMap.remove(file.getPath());
                        idUserFileMap.remove(i);
                    }
                }
                println("删除成功！");
            } else {
                error("数据库异常", Status.ERR_MYSQL);
            }
        }
    }

    //获取文件夹的大小
    public long getFSize(int fid) {
        List<Integer> fileIdList= getFileIdList(fid);
        long size=0;
        if (!fileIdList.isEmpty())  size = userFileDao.sumFileSize(fileIdList);
        return size;
    }



    //2个路径
    //rename 文件地址  新文件名
    //重命名-->自己(暂不处理)  需要大幅度改变地址
    private void rename(String p,String newName) {
        rename0(pathToFid(p),newName);
    }
    private void renameid(String id,String newName) {
        rename0(idToFid(id),newName);
    }
    private void rename0(int fid,String newName) {
        if(fid== user.getFolder_id()){
            throw new RuntimeException("不能修改根目录名称");
        }
        UserFile file = idUserFileMap.get(fid);
        if (existFName(file.getPid(), newName)) {
            throw new RuntimeException("名字重复");
        }
        //文件存在
        String newPath = idUserFileMap.get(file.getPid()).getPath() + "/" + newName;
        if (file.getPath().equals(newPath)) return;//相同不用该
        if (userFileDao.updateFname(fid, newName)) {
            //删除原地址索引，修改地址、名字
            file.setFname(newName);
            //通过循环更改文件地址
            updatePathMap(fid);
        }else{
            println("修改异常");
        }

    }

    //移动文件夹/文件 mv 原文件/夹 目标文件夹
    private void mv(String p,String target) {
        mv0(pathToFid(p),getFolder(target, true));
    }
    private void mvid(String id,String targetId) {
        mv0(idToFid(id),getFolder(targetId, false));
    }
    private void mv0(int fid,int folderFid) {
        //地址转换
        if(fid== user.getFolder_id()){
            throw new RuntimeException("不能移动根目录");
        }
        if(fid==folderFid){
            throw new RuntimeException("一样的地址");
        }
        UserFile file = idUserFileMap.get(fid);
        UserFile targetFile = idUserFileMap.get(folderFid);
        //判断名称是否存在
        if (existFName(folderFid, file.getFname())) {
            throw new RuntimeException("名称已存在！");
        }
        //进行修改
        if (userFileDao.updatePid(fid, folderFid)) {
            //从原目录下移除
            removeChild(file);
            //添加到新文件夹
            targetFile.addList(fid);
            //修改父级id,改为新文件夹下
            file.setPid(folderFid);
            updatePathMap(fid);
        }
        else {
            println("数据库修改异常");
        }
    }
}
